/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef HMFS_DATA_H
#define HMFS_DATA_H
#include <string>
#include <sys/types.h>
#include "hmfs_quota.h"

namespace OHOS {
namespace Hmfs {

namespace {
template <typename T, typename S>
inline T AlignUpCount(T value, S alignSize) {
    return (value + alignSize - 1) / alignSize;
}

constexpr uint32_t HMFS_FEATURE_ENCRYPT               = 0x0001;
constexpr uint32_t HMFS_FEATURE_BLKZONED              = 0x0002;
constexpr uint32_t HMFS_FEATURE_ATOMIC_WRITE          = 0x0004;
constexpr uint32_t HMFS_FEATURE_EXTRA_ATTR            = 0x0008;
constexpr uint32_t HMFS_FEATURE_PRJQUOTA              = 0x0010;
constexpr uint32_t HMFS_FEATURE_INODE_CHKSUM          = 0x0020;
constexpr uint32_t HMFS_FEATURE_FLEXIBLE_INLINE_XATTR = 0x0040;
constexpr uint32_t HMFS_FEATURE_QUOTA_INO             = 0x0080;
constexpr uint32_t HMFS_FEATURE_INODE_CRTIME          = 0x0100;
constexpr uint32_t HMFS_FEATURE_LOST_FOUND            = 0x0200;
constexpr uint32_t HMFS_FEATURE_VERITY                = 0x0400;
constexpr uint32_t HMFS_FEATURE_SB_CHKSUM             = 0x0800;
constexpr uint32_t HMFS_FEATURE_CASEFOLD              = 0x1000;
constexpr uint32_t HMFS_FEATURE_COMPRESSION           = 0x2000;
constexpr uint32_t HMFS_FEATURE_RO                    = 0x4000;

constexpr uint32_t MAX_DEVICE_PATH_LEN = 64;
constexpr uint32_t MAX_DEVICE_COUNT = 8;

constexpr uint64_t HMFS_MAX_DISK_SIZE = 16ULL * 1024 * 1024 * 1024 * 1024;
}

#define BITS_PER_BYTE               8
#define EXTENSION_LEN_MAX           8
#define EXTENSION_COUNT_MAX         64

#define HMFS_BLOCK_SIZE             4096
#define BLOCKS_PER_SEGMENT          512
#define HMFS_MAX_SEGMENT            (HMFS_MAX_DISK_SIZE / (HMFS_BLOCK_SIZE * BLOCKS_PER_SEGMENT))
#define HMFS_MIN_SEGMENT_COUNT      9 /* SuerBlock + (CP + SIT + NAT) * 2 + SSA + MAIN */

#define VERSION_TOTAL_LEN           256
#define VERSION_TIMESTAMP_LEN       4
#define VERSION_STRING_LEN          (VERSION_TOTAL_LEN - VERSION_TIMESTAMP_LEN)

#define VOLUME_NAME_MAX_LEN         512
#define CP_STOP_REASON_MAX          32
#define HMFS_MAX_ERRORS             16
#define DEVICE_PATH_MAX_LEN         64
#define MAX_DEVICE_COUNT            8

#define HMFS_MAX_ACTIVE_LOGS        16
#define HMFS_MAX_ACTIVE_NODE_LOGS   8
#define HMFS_MAX_ACTIVE_DATA_LOGS   8


// enum class CurSegType {
//     DATA_HOT = 0,   /* directory entry blocks */
//     DATA_WARM,      /* data blocks */
//     DATA_COLD,      /* multimedia or GCed data blocks */
//     NODE_HOT,       /* direct node blocks of directory files */
//     NODE_WARM,      /* direct node blocks of normal files */
//     NODE_COLD,      /* indirect node blocks */
//     MAX
// };

enum {
    CURSEG_DATA_HOT    = 0,    /* directory entry blocks */
    CURSEG_DATA_WARM,    /* data blocks */
    CURSEG_DATA_COLD,    /* multimedia or GCed data blocks */
    CURSEG_NODE_HOT,    /* direct node blocks of directory files */
    CURSEG_NODE_WARM,    /* direct node blocks of normal files */
    CURSEG_NODE_COLD,    /* indirect node blocks */
    CURSEG_TYPE_MAX
};

#define CURSEG_DATA_TYPE_COUNT      (3)
#define CURSEG_NODE_TYPE_COUNT      (3)


/*
 * super block area, data is writed in little-ending
 */
struct hmfs_device {
    char path[DEVICE_PATH_MAX_LEN];
    uint32_t segmentCount;
};
struct SuperBlockData {
    uint32_t magicNo;           /* Magic Number */
    uint16_t majorVersion;        /* Major Version */
    uint16_t minorVersion;        /* Minor Version */
    uint32_t logSectorSize;        /* log2 sector size in bytes */
    uint32_t logSectorsPerBlk;    /* log2 # of sectors per block */
    uint32_t logBlockSize;        /* log2 block size in bytes */
    uint32_t logBlksPerSeg;        /* log2 # of blocks per segment */
    uint32_t segsPerSection;        /* # of segments per section */
    uint32_t sectionsPerZone;        /* # of sections per zone */
    uint32_t checksumOffset;        /* checksum offset inside super block */
    uint64_t blockCount; /* total # of user blocks */
    uint32_t sectionCount;        /* total # of sections */
    uint32_t segmentCount;        /* total # of segments */
    uint32_t segmentCountInCP;    /* # of segments for checkpoint */
    uint32_t segmentCountInSIT;    /* # of segments for SIT */
    uint32_t segmentCountInNAT;    /* # of segments for NAT */
    uint32_t segmentCountInSSA;    /* # of segments for SSA */
    uint32_t segmentCountInMain;    /* # of segments for main area */
    uint32_t segment0BlkId;     /* start block address of segment 0 */
    uint32_t cpBlkId;            /* start block address of checkpoint */
    uint32_t sitBlkId;        /* start block address of SIT */
    uint32_t natBlkId;        /* start block address of NAT */
    uint32_t ssaBlkId;        /* start block address of SSA */
    uint32_t mainBlkId;        /* start block address of main area */
    uint32_t rootInodeId;        /* root inode number */
    uint32_t nodeInodeId;        /* node inode number */
    uint32_t metaInodeId;        /* meta inode number */
    uint8_t uuid[16];            /* 128-bit uuid for volume */
    uint16_t volumeName[VOLUME_NAME_MAX_LEN];    /* volume name */
    uint32_t coldExtensionCount;        /* # of cold extensions */
    char extensionList[EXTENSION_COUNT_MAX][EXTENSION_LEN_MAX];    /* extension array */
    uint32_t cpPayload;
    uint8_t version[VERSION_TOTAL_LEN];    /* the kernel version */
    uint8_t initVersion[VERSION_TOTAL_LEN];    /* the initial kernel version */
    uint32_t features;            /* defined features */
    uint8_t encryptionLevel;        /* versioning level for encryption */
    uint8_t encryptPwSalt[16];    /* Salt used for string2key algorithm */
    struct hmfs_device devices[MAX_DEVICE_COUNT];    /* device list */
    uint32_t qfInodeId[MAXQUOTAS];    /* quota inode numbers */
    uint8_t hotExtensionCount;        /* # of hot file extension */
    uint16_t  encoding;        /* Filename charset encoding */
    uint16_t  encodingFlags;    /* Filename charset encoding flags */
    uint8_t stopReason[CP_STOP_REASON_MAX];    /* stop checkpoint reason */
    uint8_t errors[HMFS_MAX_ERRORS];        /* reason of image corrupts */
    uint8_t reserved[258];        /* valid reserved region */
    uint32_t checksum;            /* checksum of superblock */
}__attribute__((packed));

#define HMFS_SUPER_BLOCK_COUNT      2
#define HMFS_MAGIC_NUMBER           0xF2F52010
#define HMFS_SUPER_BLOCK_OFFSET     1024


/*
 * SIT
 */
#define SIT_BITMAP_SIZE     (BLOCKS_PER_SEGMENT / BITS_PER_BYTE)
struct sitEntry {
    uint16_t usedBlockCount;    /* reference above */
    uint8_t blockBitmap[SIT_BITMAP_SIZE];     /* bitmap for valid blocks */
    uint64_t modTime;           /* segment age for cleaning */
} __attribute__((packed));

#define SIT_ENTRIES_PER_BLOCK     (HMFS_BLOCK_SIZE / sizeof(struct sitEntry))
struct sitBlockData {
    struct sitEntry entries[SIT_ENTRIES_PER_BLOCK];
};

#define HMFS_SIT_COUNT          2
#define SIT_MAX_BITMAP_SIZE     (AlignUpCount(AlignUpCount(HMFS_MAX_SEGMENT, SIT_ENTRIES_PER_BLOCK), HMFS_BLOCK_SIZE) \
                                * HMFS_BLOCK_SIZE / 8)



/*
 * NAT
 */
struct natEntry {
    uint8_t version;    /* latest version of cached nat entry */
    uint32_t inodeNo;   /* inode number */
    uint32_t blockId;   /* block id */
} __attribute__((packed));

#define NAT_ENTRIES_PER_BLOCK     (HMFS_BLOCK_SIZE / sizeof(struct natEntry))
struct natBlockData {
    struct natEntry entries[NAT_ENTRIES_PER_BLOCK];
};

#define HMFS_NAT_COUNT          2
#define NAT_ENTRY_PER_BLOCK (HMFS_BLKSIZE / sizeof(struct natEntry))
#define NAT_BLOCK_OFFSET(start_nid) (start_nid / NAT_ENTRY_PER_BLOCK)
#define DEFAULT_NAT_ENTRY_RATIO        20

// #define NAT_BLOCK_OFFSET(startNodeId)   ((startNodeId) / NAT_ENTRIES_PER_BLOCK)


/*
 * CP
 */
struct CheckPointData {
    uint64_t cpVersion;        /* checkpoint block version number */
    uint64_t userBlockCount;    /* # of user blocks */
    uint64_t validBlockCount;    /* # of valid blocks in main area */
    uint32_t rsvdSegmentCount;    /* # of reserved segments for gc */
    uint32_t overprovSegmentCount;    /* # of overprovision segments */
    uint32_t freeSegmentCount;    /* # of free segments in main area */

    /* information of current node segments */
    uint32_t curNodeSegNo[HMFS_MAX_ACTIVE_NODE_LOGS];
    uint16_t curNodeBlkOffset[HMFS_MAX_ACTIVE_NODE_LOGS];
    /* information of current data segments */
    uint32_t curDataSegNo[HMFS_MAX_ACTIVE_DATA_LOGS];
    uint16_t curDataBlkOffset[HMFS_MAX_ACTIVE_DATA_LOGS];
    uint32_t cpFlags;        /* Flags : umount and journal_present */
    uint32_t cpPackBlockCount;    /* total # of one cp pack */
    uint32_t cpPackStartSum;    /* start block number of data summary */
    uint32_t validNodeCount;    /* Total number of valid nodes */
    uint32_t validInodeCount;    /* Total number of valid inodes */
    uint32_t nextFreeNodeId;        /* Next free node number */
    uint32_t sitVersionBitmapSize;    /* Default value 64 */
    uint32_t natVersionBitmapSize; /* Default value 256 */
    uint32_t checksumOffset;        /* checksum offset inside cp block */
    uint64_t elapsedTime;        /* mounted time */
    /* allocation type of current segment */
    uint8_t allocType[HMFS_MAX_ACTIVE_LOGS];

    /* SIT and NAT version bitmap */
    uint8_t sitNatVersionBitmap[];
};

#define HMFS_CP_COUNT               2
#define CP_CHECKSUM_OFFSET          (HMFS_BLOCK_SIZE - sizeof(uint32_t))
#define CP_BITMAP_OFFSET            (offsetof(struct CheckPointData, sitNatVersionBitmap))
#define CP_MIN_CHECKSUM_OFFSET      CP_BITMAP_OFFSET

#define NAT_MIN_BITMAP_SIZE         64
#define CP_MAX_BITMAP_SIZE          (CP_CHECKSUM_OFFSET - CP_BITMAP_OFFSET)
#define CP_MAX_SIT_BITMAP_SIZE      (CP_MAX_BITMAP_SIZE - NAT_MIN_BITMAP_SIZE)

#define CP_FLAG_RESIZEFS            0x00004000
#define CP_FLAG_DISABLED            0x00001000
#define CP_FLAG_QUOTA_NEED_FSCK     0x00000800
#define CP_FLAG_LARGE_NAT_BITMAP    0x00000400
#define CP_FLAG_NOCRC_RECOVERY      0x00000200
#define CP_FLAG_TRIMMED             0x00000100
#define CP_FLAG_NAT_BITS            0x00000080
#define CP_FLAG_CRC_RECOVERY        0x00000040
#define CP_FLAG_FASTBOOT            0x00000020
#define CP_FLAG_FSCK                0x00000010
#define CP_FLAG_ERROR               0x00000008
#define CP_FLAG_COMPACT_SUM         0x00000004
#define CP_FLAG_ORPHAN_PRESENT      0x00000002
#define CP_FLAG_UMOUNT              0x00000001


/* a summary entry for a 4KB-sized block in a segment */
struct SummaryEntry {
    uint32_t nid;               /* parent node id */
    struct {
        uint8_t version;        /* node version number */
        uint16_t ofsInNode;   /* block index in parent node */
    } __attribute__((packed));
} __attribute__((packed));

struct NatJournalEntry {
    uint32_t nid;
    struct natEntry ne;
} __attribute__((packed));

struct SummaryFooter {
    uint8_t entryType;        /* SUM_TYPE_XXX */
    uint32_t checkSum;     /* summary checksum */
} __attribute__((packed));


#define ENTRY_COUNT_IN_SUM      512
#define SUMMARY_JOURNAL_SIZE    (HMFS_BLOCK_SIZE - sizeof(SummaryFooter) - (sizeof(SummaryEntry) * ENTRY_COUNT_IN_SUM))

#define NAT_JOURNAL_ENTRY_COUNT        ((SUMMARY_JOURNAL_SIZE - 2) / sizeof(struct NatJournalEntry))
#define NAT_JOURNAL_RESERVED_COUNT    ((SUMMARY_JOURNAL_SIZE - 2) % sizeof(struct NatJournalEntry))
#define SIT_JOURNAL_ENTRY_COUNT        ((SUMMARY_JOURNAL_SIZE - 2) / sizeof(struct SitJournalEntry))
#define SIT_JOURNAL_RESERVED_COUNT    ((SUMMARY_JOURNAL_SIZE - 2) % sizeof(struct SitJournalEntry))

struct NatJournal {
    struct NatJournalEntry entries[NAT_JOURNAL_ENTRY_COUNT];
    uint8_t reserved[NAT_JOURNAL_RESERVED_COUNT];
};

struct SitJournalEntry {
    uint32_t segno;
    struct sitEntry se;
} __attribute__((packed));

struct SatJournal {
    struct SitJournalEntry entries[SIT_JOURNAL_ENTRY_COUNT];
    uint8_t reserved[SIT_JOURNAL_RESERVED_COUNT];
};

#define EXTRA_INFO_RESERVED_SIZE    (SUMMARY_JOURNAL_SIZE - 2 - 8)

struct ExtraInfo {
    uint64_t kBytesWritten;
    uint8_t reserved[EXTRA_INFO_RESERVED_SIZE];
} __attribute__((packed));

struct JournalEntry {
    union {
        uint16_t nNats;
        uint16_t nSits;
    };
    /* spare area is used by NAT or SIT journals or extra info */
    union {
        struct NatJournal natJ;
        struct SatJournal sitJ;
        struct ExtraInfo info;
    };
} __attribute__((packed));

struct SummaryBlockData {
    struct SummaryEntry entries[ENTRY_COUNT_IN_SUM];
    struct JournalEntry journal;
    struct SummaryFooter footer;
};

#define SUMMARY_TYPE_DATA       (0)
#define SUMMARY_TYPE_NODE       (1)


struct HmfsExtent {
    uint32_t fofs;        /* start file offset of the extent */
    uint32_t blkAddr;    /* start block address of the extent */
    uint32_t len;        /* lengh of the extent */
} __attribute__((packed));

#define HMFS_NAME_LEN           255
#define ADDR_COUNT_PER_INODE    923    /* Address Pointers in an Inode */
struct HmfsInode {
    uint16_t iMode;            /* file mode */
    uint8_t iAdvise;            /* file hints */
    uint8_t iInline;            /* file inline flags */
    uint32_t iUid;            /* user ID */
    uint32_t iGid;            /* group ID */
    uint32_t iLinks;            /* links count */
    uint64_t iSize;            /* file size in bytes */
    uint64_t iBlocks;        /* file size in blocks */
    uint64_t iAtime;            /* access time */
    uint64_t iCtime;            /* change time */
    uint64_t iMtime;            /* modification time */
    uint32_t iAtimeNsec;        /* access time in nano scale */
    uint32_t iCtimeNsec;        /* change time in nano scale */
    uint32_t iMtimeNsec;        /* modification time in nano scale */
    uint32_t iGeneration;        /* file version (for NFS) */
    union {
        uint32_t iCurrentDepth;    /* only for directory depth */
        uint16_t iGcFailures;    /*
                     * # of gc failures on pinned file.
                     * only for regular files.
                     */
    };
    uint32_t iXattrNid;        /* nid to save xattr */
    uint32_t iFlags;            /* file attributes */
    uint32_t iPino;            /* parent inode number */
    uint32_t iNamelen;        /* file name length */
    uint8_t iName[HMFS_NAME_LEN];    /* file name for SPOR */
    uint8_t iDirLevel;        /* dentry_level for large dir */

    struct HmfsExtent iExt;    /* caching a largest extent */

    union {
        struct {
            uint16_t iExtraIsize;    /* extra inode attribute size */
            uint16_t iInlineXattrSize;    /* inline xattr size, unit: 4 bytes */
            uint32_t iProjid;    /* project id */
            uint32_t iInodeChecksum;/* inode meta checksum */
            uint64_t iCrtime;    /* creation time */
            uint32_t iCrtimeNsec;    /* creation time in nano scale */
            uint64_t iComprBlocks;    /* # of compressed blocks */
            uint8_t iCompressAlgrithm;    /* compress algrithm */
            uint8_t iLogClusterSize;    /* log of cluster size */
            uint16_t iPadding;        /* padding */
            uint32_t iExtraEnd[0];    /* for attribute size calculation */
        } __attribute__((packed));
        uint32_t i_addr[ADDR_COUNT_PER_INODE];    /* Pointers to data blocks */
    };
    uint32_t i_nid[5];        /* direct(2), indirect(2),
                        double_indirect(1) node id */
} __attribute__((packed));

#define F2FS_EXTRA_ISIZE_OFFSET    offsetof(struct HmfsInode, iExtraIsize)
#define F2FS_TOTAL_EXTRA_ATTR_SIZE   (offsetof(struct HmfsInode, iExtraEnd) - F2FS_EXTRA_ISIZE_OFFSET)

#define DEF_ADDRS_PER_BLOCK    1018    /* Address Pointers in a Direct Block */
struct DirectNode {
    uint32_t addr[DEF_ADDRS_PER_BLOCK];    /* array of data block address */
};

#define NIDS_PER_BLOCK          1018    /* Node IDs in an Indirect Block */
struct IndirectNode {
    uint32_t nid[NIDS_PER_BLOCK];    /* array of data block address */
};

struct NodeFooter {
    uint32_t nid;        /* node id */
    uint32_t ino;        /* inode nunmber */
    uint32_t flag;        /* include cold/fsync/dentry marks and offset */
    uint64_t cpVer;        /* checkpoint version */
    uint32_t nextBlkaddr;    /* next node page block address */
} __attribute__((packed));

struct NodeData {
    /* can be one of three types: inode, direct, and indirect types */
    union {
        struct HmfsInode i;
        struct DirectNode dn;
        struct IndirectNode in;
    };
    struct NodeFooter footer;
};

struct DirEntry {
    uint32_t hash_code; /* hash code of file name */
    uint32_t ino;       /* inode number */
    uint16_t nameLen;  /* lengh of file name */
    uint8_t fileType;  /* file type */
} __attribute__((packed));

/* the number of dentry in a block */
#define DENTRY_COUNT_IN_BLOCK    214

/* One directory entry slot covers 8bytes-long file name */
#define HMFS_SLOT_LEN        8

#define DENTRY_BITMAP_SIZE    ((DENTRY_COUNT_IN_BLOCK + BITS_PER_BYTE - 1) / BITS_PER_BYTE)
#define RESERVED_SIZE        (HMFS_BLOCK_SIZE - ((sizeof(struct DirEntry) + HMFS_SLOT_LEN) * DENTRY_COUNT_IN_BLOCK + DENTRY_BITMAP_SIZE))

struct DentryBlock {
    /* validity bitmap for directory entries in each block */
    uint8_t dentryBitmap[DENTRY_BITMAP_SIZE];
    uint8_t reserved[RESERVED_SIZE];
    struct DirEntry dentry[DENTRY_COUNT_IN_BLOCK];
    uint8_t filename[DENTRY_COUNT_IN_BLOCK][HMFS_SLOT_LEN];
};

/* file types used in inode_info->flags */
enum HMFS_FILE_TYPE {
    HMFS_FT_UNKNOWN,
    HMFS_FT_REG_FILE,
    HMFS_FT_DIR,
    HMFS_FT_CHRDEV,
    HMFS_FT_BLKDEV,
    HMFS_FT_FIFO,
    HMFS_FT_SOCK,
    HMFS_FT_SYMLINK,
    HMFS_FT_MAX,
    /* added for fsck */
    HMFS_FT_ORPHAN,
    HMFS_FT_XATTR,
    HMFS_FT_LAST_FILE_TYPE = HMFS_FT_XATTR,
};

#define LPF_STRING "lost+found"


//-------------------------
#define DEFAULT_SECTOR_SIZE         512
#define DEFAULT_SECTORS_PER_BLK     8
#define DEFAULT_DIR_LEVEL           0


//-------------------------

#define NULL_SEGNO    ((unsigned int)~0)

#ifndef SECTOR_SHIFT
#define SECTOR_SHIFT        9
#endif

/*
 * Note that f2fs_sit_entry->vblocks has the following bit-field information.
 * [15:10] : allocation type such as CURSEG_XXXX_TYPE
 * [9:0] : valid block count
 */
#define SIT_VBLOCKS_SHIFT    10
#define SIT_VBLOCKS_MASK    ((1 << SIT_VBLOCKS_SHIFT) - 1)
#define GET_SIT_VBLOCKS(raw_sit)                \
    (LE16_TO_NATIVE((raw_sit)->usedBlockCount) & SIT_VBLOCKS_MASK)
#define GET_SIT_TYPE(raw_sit)                    \
    ((LE16_TO_NATIVE((raw_sit)->usedBlockCount) & ~SIT_VBLOCKS_MASK)    \
     >> SIT_VBLOCKS_SHIFT)

} // namespace Hmfs
} // namespace OHOS
#endif
